package com.sk.util;

import com.alibaba.fastjson2.JSONObject;

import java.security.SecureRandom;
import java.util.*;
import java.util.regex.Matcher;
import java.util.regex.Pattern;
import java.util.stream.Stream;

/**
 * 字符串处理工具。
 *
 * @author smy
 */
public class StringUtil {

    public static final String rule_symbol = "*";
    public static final String code_symbol = ":";

    public static final String rang_symbol = "-";

    public static final String group_symbol = ",";

    /**
     * 正则判断
     *
     * @param content 字符串
     * @param regex   正则
     * @return 结果
     */
    public static boolean regex(String content, String regex) {
        Pattern pattern = Pattern.compile(regex);
        return pattern.matcher(content).matches();
    }

    /**
     * 基于正则提取。
     *
     * @param content 字符串
     * @param regex   正则
     * @return 提取结果
     */
    public static List<String> regexExtract(String content, String regex) {
        ArrayList<String> list = new ArrayList<>();
        Pattern p = Pattern.compile(regex);
        Matcher m = p.matcher(content);
        while (m.find()) {
            list.add(m.group());
        }
        return list;
    }

    public static String removeWhitespace(String text) {
        //去掉去除通用空白、Unicode空白字符（包括各种空白字符）
        String regexPattern = "\\s+|\\p{Z}|\\p{C}";
        return text.replaceAll(regexPattern, "");
    }


    public static boolean equalsIgnoreCase(String str1, String str2) {
        return str1 != null && str1.equalsIgnoreCase(str2);
    }

    /**
     * 范围匹配。
     *
     * @param code  编号，如 A100
     * @param range 范围，1000,A200,1000-1999,F500-,-F699,8800-8899
     * @return 是否包含。
     */
    public static boolean rangCheck(String code, String range) {
        String[] str1 = range.split(group_symbol);
        for (String s1 : str1) {
            if (s1.contains(rang_symbol)) {
                String[] str2 = s1.split(rang_symbol);
                if (str2.length == 1 && code.compareTo(str2[0]) >= 0) {
                    return true;
                }
                if (str2.length > 1 && "".equals(str2[0]) && code.compareTo(str2[1]) <= 0) {
                    return true;
                }
                if (str2.length > 1 && !"".equals(str2[0]) && code.compareTo(str2[0]) >= 0 && code.compareTo(str2[1]) <= 0) {
                    return true;
                }
            } else {
                if (code.equals(s1)) {
                    return true;
                }
            }
        }
        return false;
    }

    /**
     * 编号规则检查
     *
     * @param code 实际编号
     * @param rule 规则定义 a,*,a*,*a,
     * @return 是否符合规则
     */
    public static boolean ruleCheckOne(String code, String rule) {
        if (rule.contains(rule_symbol)) {
            if (rule_symbol.equals(rule)) {
                return true;
            } else {
                rule = rule.replace(rule_symbol, "");
                return code.contains(rule);
            }
        } else {
            return code.equals(rule);
        }
    }

    /**
     * 编号规则校验
     * 例如：sys:user:add--*,sys:*,sys:user:*,*:*:add
     *
     * @param code     实际编号
     * @param ruleCode 规则定义
     * @return 是否符合规则
     */
    public static boolean ruleCheck(String code, String ruleCode) {
        String[] cs = code.split(code_symbol);
        String[] ps = ruleCode.split(code_symbol);
        for (int i = 0; i < cs.length; i++) {
            String c = cs[i];
            String p = ps.length > i ? ps[i] : "*";
            if (!ruleCheckOne(c, p)) {
                return false;
            }
        }
        return true;
    }

    /**
     * 去掉了1,l,0,i,o几个容易混淆的字符
     */
    private static final String CODES = "23456789abcdefghjkmnpqrstuvwxyz";
    private static final SecureRandom RANDOM = new SecureRandom();

    /**
     * 随机编号生成。
     *
     * @param size 编号长度
     * @return 编号
     */
    public static String generate(int size) {
        return generate(size, CODES);
    }

    /**
     * 随机编号生成。
     *
     * @param size    编号长度
     * @param sources 内容范围
     * @return 编号
     */
    public static String generate(int size, String sources) {
        int codesLen = sources.length();
        StringBuilder code = new StringBuilder(size);
        for (int i = 0; i < size; i++) {
            code.append(sources.charAt(RANDOM.nextInt(codesLen - 1)));
        }
        return code.toString();
    }

    public static String append(Object... objects) {
        StringBuilder builder = new StringBuilder();
        for (Object o : objects) {
            builder.append(o);
        }
        return builder.toString();
    }

    public static String join(String s, Object... os) {
        StringBuilder builder = new StringBuilder();
        boolean first = true;
        for (Object o : os) {
            if (first) {
                first = false;
            } else {
                builder.append(s);
            }
            builder.append(o);
        }
        return builder.toString();
    }

    /**
     * 驼峰转下划线
     */
    public static String toUnderCase(String str) {
        if (str == null) {
            return null;
        }
        StringBuilder sb = new StringBuilder();
        // 前置字符是否大写
        boolean preCharIsUpperCase;
        // 当前字符是否大写
        boolean curreCharIsUpperCase;
        // 下一字符是否大写
        boolean nexteCharIsUpperCase = true;
        for (int i = 0; i < str.length(); i++) {
            char c = str.charAt(i);
            if (i > 0) {
                preCharIsUpperCase = Character.isUpperCase(str.charAt(i - 1));
            } else {
                preCharIsUpperCase = false;
            }
            curreCharIsUpperCase = Character.isUpperCase(c);
            if (i < (str.length() - 1)) {
                nexteCharIsUpperCase = Character.isUpperCase(str.charAt(i + 1));
            }
            if (preCharIsUpperCase && curreCharIsUpperCase && !nexteCharIsUpperCase) {
                sb.append("_");
            } else if ((i != 0 && !preCharIsUpperCase) && curreCharIsUpperCase) {
                sb.append("_");
            }
            sb.append(Character.toLowerCase(c));
        }
        return sb.toString();
    }

    /**
     * 驼峰式命名法
     */
    public static String toCamelCase(String s) {
        if (s == null) {
            return null;
        }
        s = s.toLowerCase();
        StringBuilder sb = new StringBuilder(s.length());
        boolean upperCase = false;
        for (int i = 0; i < s.length(); i++) {
            char c = s.charAt(i);
            if (c == '_') {
                upperCase = true;
            } else if (upperCase) {
                sb.append(Character.toUpperCase(c));
                upperCase = false;
            } else {
                sb.append(c);
            }
        }
        return sb.toString();
    }

    public static boolean startsWith(String value, String... keys) {
        return Stream.of(keys).anyMatch(key -> key.startsWith(value));
    }

    /**
     * 字符串匹配
     *
     * @param pattern 模板
     * @param data    匹配参数
     * @return 匹配结果
     */
    public static String pattern(String pattern, Map<String, Object> data) {
        return pattern(pattern, data, "${", "}");
    }

    /**
     * 字符串匹配
     *
     * @param pattern 模板
     * @param data    匹配参数
     * @return 匹配结果
     */
    public static String pattern(String pattern, Object data) {
        return pattern(pattern, ObjectUtil.bean2json(data), "${", "}");
    }

    public static String pattern(String pattern, Map<String, Object> data, String prefix, String suffix) {
        StringBuilder builder = new StringBuilder();
        StringBuilder keyBuilder = null;
        char[] chars = pattern.toCharArray();
        char[] pre = prefix.toCharArray();
        char[] suf = suffix.toCharArray();
        for (int p = 0; p < chars.length; p++) {
            if (eq(pre, chars, p)) {
                keyBuilder = new StringBuilder();
                p += pre.length;
            }
            if (keyBuilder != null && eq(suf, chars, p)) {
                builder.append(data.get(keyBuilder.toString()));
                p += suf.length - 1;
                keyBuilder = null;
                continue;
            }
            if (p >= chars.length) {
                break;
            }
            Objects.requireNonNullElse(keyBuilder, builder).append(chars[p]);
        }
        return builder.toString();
    }

    private static boolean eq(char[] fix, char[] chars, int point) {
        if (chars.length - point < fix.length) {
            return false;
        }
        for (int i = 0; i < fix.length; i++) {
            if (fix[i] != chars[point + i]) {
                return false;
            }
        }
        return true;
    }
}
